package com.itheima.service.impl;

import com.itheima.mapper.SetmealMapper;
import com.itheima.pojo.*;
import com.itheima.service.ReportService;
import com.itheima.mapper.MemberMapper;
import com.itheima.mapper.OrderMapper;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Encounter
 * @date 2024/10/16 17:22<br/>
 */
@Service
public class ReportServiceImpl implements ReportService
    {
        @Autowired
        private MemberMapper memberMapper;
        
        @Autowired
        private SetmealMapper setmealMapper;
        
        @Autowired
        private OrderMapper orderMapper;
        
        /**
         * 获取成员报告
         *
         * @return {@link MemberReportVO }
         */
        @Override
        public MemberReportVO getMemberReport()
            {
                //执行查询
                List<Map<String, Object>> result = memberMapper.getMemberCount();
                //拆分查询结果
                List<String> months = new ArrayList<>();
                List<Long> memberCount = new ArrayList<>();
                for (Map<String, Object> map : result)
                    {
                        //获取月份并改为相应格式
                        Date date = (Date) map.get("months");
                        DateFormat targetFormat = new SimpleDateFormat("yyyy.MM.dd");
                        String target = targetFormat.format(date);
                        months.add(target);
                        
                        //存入当前月份对应的会员数
                        memberCount.add((Long) map.get("memberCount"));
                    }
                
                //封装并返回对象
                return MemberReportVO.builder()
                        .months(months)
                        .memberCount(memberCount)
                        .build();
            }
        
        /**
         * 获取 SetMeal 报告
         *
         * @return {@link SetmealReportVO }
         */
        @Override
        public SetmealReportVO getSetmealReport()
            {
                //先查询订单中所有有关的套餐
                List<SetmealCount> setmealCounts = orderMapper.querySetmealCount();
                //将套餐名存储起来
                List<String> setmealNames = setmealCounts.stream()
                        .map(SetmealCount::getName)
                        .distinct()
                        .collect(Collectors.toList());
                
                //封装返回结果
                return SetmealReportVO.builder()
                        .setmealNames(setmealNames)
                        .setmealCount(setmealCounts)
                        .build();
            }
        
        /**
         * 获取业务报告数据
         *
         * @return {@link BusinessReportVO }
         */
        @Override
        public BusinessReportVO getBusinessReportData()
            {
                //报告日期
                LocalDate todayDate = LocalDate.now();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                String today = todayDate.format(formatter);
                
                //获取今日到访次数，订单中为“已到诊”
                Integer todayVisitsNumber = orderMapper.getTodayVisitsNumber(today);
                
                //今日新增会员数
                Integer todayNewMember = memberMapper.getTodayNewMember(today);
                
                //本周到访次数
                //获取周一
                LocalDate mondayDate = todayDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                String monday = mondayDate.format(formatter);
                Integer thisWeekVisitsNumber = orderMapper.getVisitsNumber(monday, today);
                
                //热门套餐
                List<Map<String, Object>> hotSetmealList = orderMapper.getHotSetmeal();
                List<HotSetmeal> hotSetmeals = new ArrayList<>();
                for (Map<String, Object> hotSetmealMap : hotSetmealList)
                    {
                        HotSetmeal hotSetmeal = new HotSetmeal();
                        BigDecimal proportion = (BigDecimal) hotSetmealMap.get("proportion");
                        hotSetmeal.setProportion(proportion.doubleValue());
                        hotSetmeal.setName(hotSetmealMap.get("name").toString());
                        Long setmealCount = (Long) hotSetmealMap.get("setmealCount");
                        hotSetmeal.setSetmealCount(setmealCount.intValue());
                        hotSetmeals.add(hotSetmeal);
                    }
                
                //本月新增会员数
                //获取本月第一天
                LocalDate firstDayOfMonthDate = todayDate.with(TemporalAdjusters.firstDayOfMonth());
                String firstDayOfMonth = firstDayOfMonthDate.format(formatter);
                Integer thisMonthNewMember = memberMapper.getNewMember(firstDayOfMonth, today);
                
                //本周新增会员数
                Integer thisWeekNewMember = memberMapper.getNewMember(monday, today);
                
                //会员总数
                Integer totalMember = memberMapper.getTotalMember();
                
                //本月订单数
                Integer thisMonthOrderNumber = orderMapper.getOrderNumber(firstDayOfMonth, today);
                
                //本月访问次数
                Integer thisMonthVisitsNumber = orderMapper.getVisitsNumber(firstDayOfMonth, today);
                
                //订单总数
                Integer totalOrderNumber = orderMapper.getAllCount();
                
                //本周订单总数
                Integer thisWeekOrderNumber = orderMapper.getOrderNumber(monday, today);
                
                //封装返回数据
                return BusinessReportVO.builder()
                        .todayVisitsNumber(todayVisitsNumber)
                        .reportDate(today)
                        .todayNewMember(todayNewMember)
                        .thisWeekVisitsNumber(thisWeekVisitsNumber)
                        .hotSetmeal(hotSetmeals)
                        .thisMonthNewMember(thisMonthNewMember)
                        .thisWeekNewMember(thisWeekNewMember)
                        .totalMember(totalMember)
                        .thisMonthOrderNumber(thisMonthOrderNumber)
                        .thisMonthVisitsNumber(thisMonthVisitsNumber)
                        .totalOrderNumber(totalOrderNumber)
                        .thisWeekOrderNumber(thisWeekOrderNumber)
                        .build();
            }
        
        /**
         * 导出报告
         */
        @Override
        public void exportReport(HttpServletResponse response)
            {
                // 设置响应头
                response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                response.setHeader("Content-Disposition", "attachment; filename=\"operational_data_reports.xlsx\"");
                //获取模板
                try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("templates/report_template.xlsx");
                     XSSFWorkbook excel = new XSSFWorkbook(is))
                    {
                        //获取运营数据
                        BusinessReportVO businessReportData = getBusinessReportData();
                        
                        //获取sheet页
                        XSSFSheet sheet = excel.getSheet("Sheet1");
                        
                        //填充报告日期
                        sheet.getRow(2).getCell(5).setCellValue(businessReportData.getReportDate());
                        
                        //会员数据统计
                        //新增会员数
                        XSSFRow row4 = sheet.getRow(4);
                        row4.getCell(5).setCellValue(businessReportData.getTodayNewMember());
                        //总会员数
                        row4.getCell(7).setCellValue(businessReportData.getTotalMember());
                        //本周新增
                        XSSFRow row5 = sheet.getRow(5);
                        row5.getCell(5).setCellValue(businessReportData.getThisWeekNewMember());
                        //本月新增
                        row5.getCell(7).setCellValue(businessReportData.getThisMonthNewMember());
                        
                        //预约到诊数据统计
                        XSSFRow row7 = sheet.getRow(7);
                        //今日预约数
                        row7.getCell(5).setCellValue(businessReportData.getTotalOrderNumber());
                        //今日到诊数
                        row7.getCell(7).setCellValue(businessReportData.getTodayVisitsNumber());
                        //本周预约数
                        XSSFRow row8 = sheet.getRow(8);
                        row8.getCell(5).setCellValue(businessReportData.getThisWeekOrderNumber());
                        //本周到诊数
                        row8.getCell(7).setCellValue(businessReportData.getThisMonthVisitsNumber());
                        //本月预约数
                        XSSFRow row9 = sheet.getRow(9);
                        row9.getCell(5).setCellValue(businessReportData.getThisMonthOrderNumber());
                        //本月到诊数
                        row9.getCell(7).setCellValue(businessReportData.getThisMonthVisitsNumber());
                        
                        //热门套餐
                        for (int i = 12; i <= 15; i++)
                            {
                                XSSFRow row = sheet.getRow(i);
                                HotSetmeal hotSetmeal = businessReportData.getHotSetmeal().get(i - 12);
                                //套餐名
                                row.getCell(4).setCellValue(hotSetmeal.getName());
                                //套餐
                                row.getCell(5).setCellValue(hotSetmeal.getSetmealCount());
                                row.getCell(6).setCellValue(hotSetmeal.getProportion());
                                Map<String, Object> map = new HashMap<>();
                                map.put("name", hotSetmeal.getName());
                                row.getCell(7).setCellValue(setmealMapper.query(map).get(0).getRemark());
                            }
                        
                        //数据填充完毕，推送下载
                        excel.write(response.getOutputStream());
                    }
                catch (IOException e)
                    {
                        throw new RuntimeException(e);
                    }
            }
        
    }
